import 'package:decimal/decimal.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:lib_uikit/generated/l10n.dart';
import 'package:lib_uikit/theme/gt_colors_v3.dart';
import 'package:lib_core/lib_core.dart';
import 'chart_xy_value_utils.dart';
import 'model/chart_dot_data.dart';
import 'model/chart_xy_data.dart';
import 'package:lib_uikit/lib_uikit.dart';

/// @Title   柱状图页面
/// @Author: bryce
/// @CreateDate:  2023/8/17 16:32
class ChartBarWidget extends StatefulWidget {
  /// 数据描点：1：必须是连续日期，2：日期数量需大于等于四
  final List<ChartDotData> dots;
  final double height;
  final Color topColor;
  final Color bottomColor;
  final bool enableTouch;
  final double rightPadding;

  /// 这两个值可不传，会根据dots的最大最小值动态算
  final double? minY;
  final double? maxY;

  /// 柱子宽度: 若不是特殊的需求，建议不传这个参数，会动态计算最大宽度
  /// 如果传了宽度的话，若剩余空间不够，则柱子间隔设为1，剩余空间平分作为柱子宽度
  final double? barWidth;

  /// 是否仅展示x轴的收尾坐标
  final bool onlyShowFirstLastBottomTitle;

  /// 提示内容是否全部在柱子顶部显示
  final bool showingTooltipIndicatorsOnTop;

  /// 触摸图表时弹框内的内容
  /// 默认实现为：widget.showingTooltipIndicatorsOnTop
  ///        ? BarTooltipItem(
  ///            GTNumberFormat.formatNumberKM(dot.value),
  ///            gtTextStyleW500(color: dot.value > 0 ? widget.topColor : widget.bottomColor, fontSize: 12),
  ///          )
  ///        : BarTooltipItem('${dot.date} \n',
  ///            gtTextStyleW500(color: GTColorsV3.uikitText2V3.dark, fontSize: 12).copyWith(height: 1 + 8 / 12),
  ///            textAlign: TextAlign.start,
  ///            textDirection: GTThemeProvider.instance.isRTL() ? TextDirection.rtl : TextDirection.ltr,
  ///            children: [
  ///                TextSpan(text: '${LibUIKitS.current.return_profit} '),
  ///                TextSpan(
  ///                  text: GTNumberFormat.formatNumberKM(dot.value),
  ///                  style: gtTextStyleW500(color: GTColorsV3.uikitText6V3.color, fontSize: 12),
  ///                )
  ///              ])
  final BarTooltipItem Function(int index, ChartDotData dots)? buildTooltipItem;

  /// 根据y值value获取左侧显示的文案，如不传则默认千分位展示
  final String Function(double y)? getLeftTitleByY;

  /// 是否在触摸结束时消失tip框
  final bool dismissTouchPopWhenTouchEnd;

  /// 是否允许展示触摸指示线
  final bool enableTouchIndicator;

  /// 触摸手势的回调，参数isTouchInSpot代表触摸时是否在某个点上
  /// isTouchInSpot为false时包括手势移动到非描点处、手势抬起、手势取消；只有在手势触摸在描点上时才会为true
  final Function(bool isTouchInSpot)? onTouchSpotsListener;

  /// 是否展示所有x轴(默认为false会展示3-5个坐标)
  final bool showAllBottomTitles;

  /// x轴的固定间隔(如果不传会自动计算，传入的话需要注意间隔太小的话会放不下)
  final int? xInterval;

  /// 设置图表行高，设置这个参数时，height 不生效
  final double? chartRowHeight;

  const ChartBarWidget(
      {super.key,
      required this.dots,
      required this.topColor,
      required this.bottomColor,
      this.buildTooltipItem,
      this.getLeftTitleByY,
      this.minY,
      this.maxY,
      this.barWidth,
      this.showingTooltipIndicatorsOnTop = false,
      this.enableTouch = true,
      this.onlyShowFirstLastBottomTitle = false,
      this.dismissTouchPopWhenTouchEnd = false,
      this.enableTouchIndicator = true,
      this.showAllBottomTitles = false,
      this.onTouchSpotsListener,
      this.xInterval,
      this.rightPadding = 10,
      this.height = 300,
      this.chartRowHeight});

  @override
  State<StatefulWidget> createState() => _ChartBarWidgetState();
}

class _ChartBarWidgetState extends State<ChartBarWidget> {
  // bar最大的宽度
  double _barMaxWidth = 16;

  // bar之间最小的间隔
  static const double _barMinSpace = 1;

  double? barWidth;

  // bar之间的间距
  double barSpace = 2;

  // XY相关数据
  late ChartXYData chartXYData;

  @override
  void initState() {
    super.initState();
    // 初始化计算XY相关数据
    chartXYData = ChartXYValueUtils.calculateChartXYData(widget.dots,
        cutY: 0,
        isCurvedLine: false,
        customMinY: widget.minY,
        customMaxY: widget.maxY,
        addYIntervalUpDownCount: widget.showingTooltipIndicatorsOnTop ? 1 : 0,
        xInterval: widget.xInterval);
    if (null != widget.barWidth) {
      _barMaxWidth = widget.barWidth!;
    }
  }

  @override
  Widget build(BuildContext context) {
    // 计算bar宽度
    if (null == barWidth) {
      double allWidth = MediaQuery.of(context).size.width - 60;
      int barLength = widget.dots.length;
      int barSpaceLength = barLength + 1;

      double allBarMaxWidth = _barMaxWidth * barLength;
      double allBarMinSpace = _barMinSpace * barSpaceLength;

      if (allWidth - allBarMaxWidth > allBarMinSpace) {
        // 如果bar最大宽度时间距是够的，则bar使用最大宽度，间距再算
        barSpace = (allWidth - allBarMaxWidth) / barSpaceLength;
        barWidth = _barMaxWidth;
      } else {
        // 如果bar最大宽度时间距不够，则间距使用最小间距，bar宽度再算
        barSpace = _barMinSpace;
        // 后面* 95 / 100是为了防止最后一条柱被切
        barWidth = ((allWidth - allBarMinSpace) / barLength) * 95 / 100;
      }
    }

    return Padding(
        // 加这个边距的原因是防止最后的点被切掉
        padding: GTEdgeInsetsOnly(right: widget.rightPadding),
        child: SizedBox(
          height: widget.chartRowHeight != null
              ? widget.chartRowHeight! * (chartXYData.maxYChart - chartXYData.minYChart) / chartXYData.yIntervalChart +
                  30
              : widget.height,
          child: BarChart(
            mainBarData(),
            swapAnimationDuration: const Duration(milliseconds: 250),
          ),
        ));
  }

  BarChartData mainBarData() {
    TextStyle leftTitleStyle = gtTextStyleW400(color: GTColorsV3.text3.color, fontSize: 10);
    TextStyle bottomTitleStyle = TextStyle(color: GTColorsV3.text3.color, fontSize: 10);

    int maxLength = 0;
    String maxLengthValueStr = '';
    for (double i = chartXYData.minYChart; i <= chartXYData.maxYChart; i += chartXYData.yIntervalChart) {
      String tempStr = _getLeftTitleByY(i);
      if (tempStr.length > maxLength) {
        maxLength = tempStr.length;
        maxLengthValueStr = tempStr;
      }
    }
    double leftMaxWidth = TextUtils.calculateTextSize(context, '$maxLengthValueStr  ', textStyle: leftTitleStyle).width;

    AxisTitles? chartLeftTitles = AxisTitles(
      sideTitles: SideTitles(
        showTitles: true,
        getTitlesWidget: (value, meta) => leftTitles(value, meta, leftTitleStyle),
        interval: chartXYData.yIntervalChart,
        reservedSize: leftMaxWidth + 10,
      ),
    );

    // 单个柱子下方文案的最大宽度（如果不设置的话为0则不限制，在下方标题全展示的情况下会设置）
    double singleBottomTitleMaxWidth = 0;
    double bottomHeight = 30;
    if (widget.showAllBottomTitles) {
      // 计算在全部显示底部标题的情况下，单个柱子下方文案的最大宽度
      // 计算公式：(屏幕宽度-左侧标题宽度-10)/文案个数-单个文案左右边距
      singleBottomTitleMaxWidth = (GTScreen.width - leftMaxWidth - widget.rightPadding - 10) / widget.dots.length - 10;
      if (singleBottomTitleMaxWidth > 0) {
        String bottomMaxTitle = getBottomMaxTitle();
        double bottomTitleMaxWidth =
            TextUtils.calculateTextSize(context, bottomMaxTitle, textStyle: bottomTitleStyle).width;
        if (bottomTitleMaxWidth > singleBottomTitleMaxWidth) {
          bottomHeight = 40;
        }
      }
    }

    return BarChartData(
      alignment: BarChartAlignment.center,
      maxY: chartXYData.maxYChart,
      minY: chartXYData.minYChart,
      groupsSpace: barSpace,
      barTouchData: BarTouchData(
          enabled: widget.enableTouch,
          handleBuiltInTouches: widget.enableTouchIndicator,
          touchCallback: (FlTouchEvent event, BarTouchResponse? touchResponse) {
            if (!event.isInterestedForInteractions || touchResponse == null || touchResponse.spot == null) {
              // 不显示Tooltips
              widget.onTouchSpotsListener?.call(false);
            } else {
              widget.onTouchSpotsListener?.call(true);
            }
          },
          // 是否在触摸结束时消失tip框
          dismissTouchPopWhenTouchEnd: widget.dismissTouchPopWhenTouchEnd,
          touchExtraThreshold: GTEdgeInsetsFormRTLB(10, 100, 10, 100),
          indicatorColor: GTColorsV3.uikitDivider4V3.color,
          indicatorStrokeWidth: 1,
          touchTooltipData: BarTouchTooltipData(
            tooltipBgColor: widget.showingTooltipIndicatorsOnTop ? Colors.transparent : GTColorsV3.uikitCmpt6V3.color,
            fitInsideHorizontally: true,
            fitInsideVertically: true,
            tooltipPadding: widget.showingTooltipIndicatorsOnTop
                ? EdgeInsets.zero
                : const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
            tooltipMargin: widget.showingTooltipIndicatorsOnTop ? 0 : 16,
            getTooltipItem: (BarChartGroupData group, int groupIndex, BarChartRodData rod, int rodIndex) {
              int index = group.x.toInt();
              ChartDotData dot = widget.dots[index];
              return widget.buildTooltipItem?.call(index, dot) ?? _defaultTooltipItem(index, dot);
            },
          )),
      titlesData: FlTitlesData(
        show: true,
        topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
        rightTitles:
            GTThemeProvider.instance.isRTL() ? chartLeftTitles : AxisTitles(sideTitles: SideTitles(showTitles: false)),
        bottomTitles: AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            reservedSize: bottomHeight,
            getTitlesWidget: (double value, TitleMeta meta) =>
                bottomTitles(bottomTitleStyle, singleBottomTitleMaxWidth, value, meta),
          ),
        ),
        leftTitles:
            GTThemeProvider.instance.isRTL() ? AxisTitles(sideTitles: SideTitles(showTitles: false)) : chartLeftTitles,
      ),
      gridData: FlGridData(
        drawVerticalLine: false, // 是否隐藏垂直线
        horizontalInterval: chartXYData.yIntervalChart, // 水平线的间隔值
        getDrawingHorizontalLine: (double value) {
          return FlLine(color: GTColorsV3.divider1.color, strokeWidth: value == 0 ? 2 : 1);
        },
      ),
      borderData:
          FlBorderData(show: true, border: Border(bottom: BorderSide(color: GTColorsV3.divider1.color, width: 1))),
      barGroups: widget.dots
          .asMap()
          .entries
          .map((e) => generateGroup(e.key, GTNumberFormat.getNumMultiply(e.value.value, chartXYData.yMultiplier)))
          .toList(),
    );
  }

  String getBottomMaxTitle() {
    String bottomMaxTitle = '';
    for (var element in widget.dots) {
      if (bottomMaxTitle.length < element.date.length) {
        bottomMaxTitle = element.date;
      }
    }
    return bottomMaxTitle;
  }

  Widget bottomTitles(TextStyle bottomTitleStyle, double singleBottomTitleMaxWidth, double value, TitleMeta meta) {
    int currentIndex = value.toInt();
    bool showTitle = false;
    if (widget.showAllBottomTitles) {
      showTitle = true;
    } else {
      if (widget.onlyShowFirstLastBottomTitle) {
        if (currentIndex == 0 || currentIndex == chartXYData.maxX) {
          showTitle = true;
        } else {
          showTitle = false;
        }
      } else {
        if (chartXYData.maxX < 4 || (chartXYData.maxX - currentIndex) % chartXYData.xInterval == 0) {
          showTitle = true;
        } else {
          showTitle = false;
        }
      }
    }

    if (showTitle) {
      return SideTitleWidget(
        axisSide: meta.axisSide,
        fitInside: SideTitleFitInsideData.fromTitleMeta(meta),
        child: Container(
            alignment: Alignment.center,
            constraints:
                BoxConstraints(maxWidth: singleBottomTitleMaxWidth <= 0 ? double.infinity : singleBottomTitleMaxWidth),
            child: Text(
              widget.dots[value.toInt()].date ?? '',
              style: bottomTitleStyle,
              maxLines: 2,
              overflow: TextOverflow.clip,
            )),
      );
    } else {
      return Container();
    }
  }

  Widget leftTitles(double value, TitleMeta meta, TextStyle leftTitleStyle) {
    Decimal result = Decimal.parse('$value') % Decimal.parse('${chartXYData.yIntervalChart}');
    if (result.toDouble() == 0) {
      return SideTitleWidget(
        axisSide: meta.axisSide,
        child: Text(
          _getLeftTitleByY(GTNumberFormat.getNumDivision(value, chartXYData.yMultiplier)),
          style: leftTitleStyle,
          textAlign: TextAlign.center,
        ),
      );
    } else {
      return Container();
    }
  }

  BarChartGroupData generateGroup(int x, double value) {
    final isTop = value > 0;
    // final isTouched = touchedIndex == x;
    return BarChartGroupData(
      x: x,
      groupVertically: true,
      // showingTooltipIndicators: [0] ,
      showingTooltipIndicatorsOnTop: widget.showingTooltipIndicatorsOnTop,
      barRods: [
        BarChartRodData(
          fromY: 0,
          toY: value,
          width: barWidth,
          borderRadius: BorderRadius.zero,
          color: isTop ? widget.topColor : widget.bottomColor,
        )
      ],
    );
  }

  BarTooltipItem _defaultTooltipItem(int index, ChartDotData dot) {
    return widget.showingTooltipIndicatorsOnTop
        ? BarTooltipItem(
            GTNumberFormat.formatNumberKM(dot.value),
            gtTextStyleW500(color: dot.value > 0 ? widget.topColor : widget.bottomColor, fontSize: 12),
          )
        : BarTooltipItem('${dot.date} \n',
            gtTextStyleW500(color: GTColorsV3.uikitText2V3.dark, fontSize: 12).copyWith(height: 1 + 8 / 12),
            textAlign: TextAlign.start,
            textDirection: GTThemeProvider.instance.isRTL() ? TextDirection.rtl : TextDirection.ltr,
            children: [
                TextSpan(text: '${LibUIKitS.current.return_profit} '),
                TextSpan(
                  text: GTNumberFormat.formatNumberKM(dot.value),
                  style: gtTextStyleW500(color: GTColorsV3.uikitText6V3.color, fontSize: 12),
                )
              ]);
  }

  String _getLeftTitleByY(double value) {
    return null != widget.getLeftTitleByY
        ? widget.getLeftTitleByY!(value)
        : GTNumberFormat.formatNumberThousands(value, maxFractionDigits: 10);
  }
}
